Skip to content

fix(expo): link iOS SDK through podspec SPM dependencies#8927

Merged
wobsoriano merged 5 commits into
mainfrom
mike/fix-expo-ios-spm-podspec-linking
Jun 19, 2026
Merged

fix(expo): link iOS SDK through podspec SPM dependencies#8927
wobsoriano merged 5 commits into
mainfrom
mike/fix-expo-ios-spm-podspec-linking

Conversation

@mikepitre

@mikepitre mikepitre commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Link clerk-ios from ClerkExpo.podspec using React Native's spm_dependency, so the ClerkExpo pod target can import ClerkKit and ClerkKitUI directly.
  • Remove the config plugin's app-target SPM/project mutation and copied native bridge injection.
  • Remove the old optional native bridge facade now that the Clerk iOS SDK is available inside the ClerkExpo pod target; module and view wrappers call ClerkNativeBridge.shared directly.
  • Bump the @clerk/expo React Native peer dependency from >=0.73 to >=0.75, since this fix relies on React Native's podspec Swift Package Manager dependency support.

Motivation

Expo SDK 54 generates import ClerkExpo for Expo modules while SDK 56 generates internal import ClerkExpo. The import form is not the real problem; the issue was that ClerkExpo depended on ClerkKit/ClerkKitUI through app-target project mutation instead of declaring the Swift package dependency on the pod target that actually imports those modules.

Moving the SPM dependency into the podspec keeps the dependency attached to the correct native target and avoids having to special-case Expo's generated import style.

Because the Clerk iOS SDK is now visible to the pod target, the separate ClerkExpoBridge.swift protocol/global registry layer is no longer needed. The remaining readiness and native-client-change coordination lives on ClerkNativeBridge.

Verification

  • git diff --check
  • pnpm --filter @clerk/expo test
  • Fresh Expo SDK 54 and SDK 56 apps installed @clerk/expo from a packed tarball
  • npx expo prebuild --clean --platform ios passed for both apps
  • Clean Release simulator builds passed for both apps, fetching clerk-ios 1.2.4 through SPM
  • Installed and launched both apps on the iOS simulator; verified AuthView, UserButton, JS sign-in, and JS sign-out

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Improved iOS development-build compatibility across Expo SDK versions with more reliable native SDK linking and configuration.
    • Refined native-to-JS client-change updates to stay consistent after app reconfiguration and theme loading.
  • Chores

    • Simplified iOS setup by reading the host SDK version from app metadata and using it when communicating with the native layer.
  • Tests

    • Removed an obsolete iOS version injection test.
  • Compatibility

    • Raised the minimum supported React Native version to 0.75+.

@changeset-bot

changeset-bot Bot commented Jun 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: ea697ef

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@clerk/expo Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Jun 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview, Comment Jun 19, 2026 9:42am
swingset Ready Ready Preview, Comment Jun 19, 2026 9:42am

Request Review

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: f46b3e8a-ee41-4167-8d6d-9d6271d22c1e

📥 Commits

Reviewing files that changed from the base of the PR and between ee5f933 and ea697ef.

📒 Files selected for processing (1)
  • .changeset/tidy-expo-ios-import.md
✅ Files skipped from review due to trivial changes (1)
  • .changeset/tidy-expo-ios-import.md

📝 Walkthrough

Walkthrough

The Clerk iOS SDK is now linked via React Native's native SPM podspec support rather than manual Expo config plugin injection. ClerkExpo.podspec declares the SPM dependency and expands its source file list. ClerkNativeBridge is refactored to a static observer/emitter pattern reading the SDK version from Info.plist. app.plugin.js is reduced to setting only the deployment target and writing ClerkExpoVersion to Info.plist.

Changes

iOS SPM Podspec Integration

Layer / File(s) Summary
Podspec SPM dependency declaration and source files
packages/expo/ios/ClerkExpo.podspec, packages/expo/package.json
Podspec pins clerk_ios_version to 1.2.4, adds a conditional SPM block for ClerkKit/ClerkKitUI, expands s.source_files to cover all native bridge and view manager files, and raises the react-native peer dependency minimum to >=0.75.
ClerkNativeBridge static observer/emitter refactor and Info.plist version
packages/expo/ios/ClerkNativeBridge.swift
ClerkExpoHeaderMiddleware reads hostSdkVersion from Bundle.main Info.plist key ClerkExpoVersion at runtime instead of a build-time placeholder. configure gains an early loadThemes() call. Readiness and client-change plumbing is replaced with new static addReadyObserver/removeReadyObserver/emitReady and setClientChangedEmitter/emitClientChanged methods. Reconfigure path now posts a notification instead of emitting bridge-ready events.
ClerkExpoModule decoupled from optional bridge instance
packages/expo/ios/ClerkExpoModule.swift
Removes all top-level bridge protocol, event enum, observer registry, and global bridge variable declarations. Initializer registers a client-changed emitter via ClerkNativeBridge.setClientChangedEmitter. configure, getClientToken, and syncFromJsClientToken call ClerkNativeBridge.shared directly instead of guarding on an optional instance. The free function emitClerkNativeClientChanged is removed.
Native views switched to ClerkNativeBridge.shared singleton
packages/expo/ios/ClerkNativeViewHost.swift, packages/expo/ios/ClerkAuthNativeView.swift, packages/expo/ios/ClerkUserButtonNativeView.swift, packages/expo/ios/ClerkUserProfileNativeView.swift
ClerkNativeViewHost removes ClerkNativeBridgeReadyObserver conformance and switches to NotificationCenter observation of .clerkNativeSDKDidConfigure, adding explicit observer removal on window detach and in deinit. The three native view controllers replace guarded optional bridge lookups with direct ClerkNativeBridge.shared calls.
app.plugin.js simplification and changeset
packages/expo/app.plugin.js, .changeset/tidy-expo-ios-import.md
Removes all SPM injection, bridge file copying, AppDelegate method injection, and Podfile post-install hook logic from app.plugin.js, leaving only a deployment target update and an Info.plist ClerkExpoVersion write. Documentation is updated to reflect the simplified setup. A patch changeset documents the iOS build fix.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • clerk/javascript#8883: Replaces the __CLERK_EXPO_VERSION__ placeholder injection and ClerkExpoHeaderMiddleware request header wiring that this PR refactors to use Info.plist-driven runtime version reading.
  • clerk/javascript#8867: Pins clerk-ios to 1.2.4 in iOS integration, matching the version now declared via clerk_ios_version in the podspec.
  • clerk/javascript#8920: Modifies ClerkNativeBridge.swift in the configure/readiness signaling path, directly overlapping with this PR's refactoring of emitReady and loadThemes call placement.

Suggested reviewers

  • wobsoriano

Poem

🐇 No more Podfile hooks to fear,
The SPM lives in the podspec near!
Info.plist holds the version now,
The singleton bridge takes a bow.
Less plugin code, cleaner deploy —
This bunny hops with iOS joy! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.24% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: moving iOS SDK linking from app-target configuration to podspec SPM dependencies.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new

pkg-pr-new Bot commented Jun 19, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@8927

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@8927

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@8927

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@8927

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@8927

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@8927

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@8927

@clerk/express

npm i https://pkg.pr.new/@clerk/express@8927

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@8927

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@8927

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@8927

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@8927

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@8927

@clerk/react

npm i https://pkg.pr.new/@clerk/react@8927

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@8927

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@8927

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@8927

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@8927

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@8927

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@8927

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@8927

commit: ea697ef

@github-actions

github-actions Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-06-19T09:43:45.347Z

Summary

Metric Count
Packages analyzed 19
Packages with changes 0
🔴 Breaking changes 0
🟡 Non-breaking changes 0
🟢 Additions 0

No API Changes Detected

All packages have stable APIs with no detected changes.


Report generated by Break Check

Last ran on ea697ef.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/expo/ios/ClerkExpo.podspec (1)

20-21: 💤 Low value

Consider externalizing the Clerk iOS SDK version.

The clerk_ios_version = '1.2.4' is hardcoded in the podspec. Every Clerk iOS SDK update will require manually editing this file. Consider whether the version could be read from package.json or another configuration source to reduce maintenance overhead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/expo/ios/ClerkExpo.podspec` around lines 20 - 21, The
clerk_ios_version variable is hardcoded as '1.2.4' in the podspec file,
requiring manual updates whenever the Clerk iOS SDK version changes. Externalize
this version by reading it from package.json or another centralized
configuration source instead of hardcoding it. Modify the clerk_ios_version
assignment to dynamically fetch the version from the appropriate configuration
file, reducing maintenance overhead and keeping the dependency version
synchronized across your project.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/expo/ios/ClerkExpoBridge.swift`:
- Around line 36-58: The clerkNativeBridgeReadyObservers hash table is accessed
without synchronization in the methods addClerkNativeBridgeReadyObserver,
removeClerkNativeBridgeReadyObserver, and emitClerkNativeBridgeReady, and
similarly clerkNativeClientChangedEmitter is accessed in
setClerkNativeClientChangedEmitter and emitClerkNativeClientChanged without
synchronization. Since NSHashTable is not thread-safe, concurrent calls from
different threads can corrupt the data structure or cause crashes. Create a
private serial DispatchQueue and wrap all accesses to both
clerkNativeBridgeReadyObservers and clerkNativeClientChangedEmitter within
synchronized blocks using this queue, ensuring all read and write operations are
serialized and thread-safe.

---

Nitpick comments:
In `@packages/expo/ios/ClerkExpo.podspec`:
- Around line 20-21: The clerk_ios_version variable is hardcoded as '1.2.4' in
the podspec file, requiring manual updates whenever the Clerk iOS SDK version
changes. Externalize this version by reading it from package.json or another
centralized configuration source instead of hardcoding it. Modify the
clerk_ios_version assignment to dynamically fetch the version from the
appropriate configuration file, reducing maintenance overhead and keeping the
dependency version synchronized across your project.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 1cfed06c-5d52-4b43-bbe1-7a2655f71514

📥 Commits

Reviewing files that changed from the base of the PR and between 88525a6 and 5faa0bc.

📒 Files selected for processing (8)
  • .changeset/tidy-expo-ios-import.md
  • packages/expo/app.plugin.js
  • packages/expo/ios/ClerkExpo.podspec
  • packages/expo/ios/ClerkExpoBridge.swift
  • packages/expo/ios/ClerkExpoModule.swift
  • packages/expo/ios/ClerkNativeBridge.swift
  • packages/expo/package.json
  • packages/expo/src/__tests__/appPlugin.injectClerkExpoVersion.test.js
💤 Files with no reviewable changes (1)
  • packages/expo/src/tests/appPlugin.injectClerkExpoVersion.test.js

Comment thread packages/expo/ios/ClerkExpoBridge.swift Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f7088d0604

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/expo/app.plugin.js

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 83e37e979b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

products: ['ClerkKit', 'ClerkKitUI']
)
else
raise 'ClerkExpo requires React Native 0.75 or newer for iOS Swift Package Manager dependencies.'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep RN 0.73/0.74 pod installs working

For apps still on React Native 0.73/0.74 (which satisfied @clerk/expo's previous peer range and can receive this patch via a caret range), spm_dependency is not defined by RN's CocoaPods scripts, so this raise makes every iOS pod install fail even though those apps built with the old Xcode-project injection path. Because this is being released as a patch, please keep a fallback for those RN versions or avoid shipping this path to them.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our supported expo range is >=53, so supporting 0.73 and 0.74 is already a mismatch. Expo 53 contains React Native 0.79

@wobsoriano wobsoriano left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested this locally in both Expo SDK 54 and 56. Runs successfully ✅

@wobsoriano wobsoriano merged commit bfe280a into main Jun 19, 2026
49 checks passed
@wobsoriano wobsoriano deleted the mike/fix-expo-ios-spm-podspec-linking branch June 19, 2026 10:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants